package com.tbvtc.agriculturalcreditchainserver2025.utils;

import com.tbvtc.agriculturalcreditchainserver2025.properties.ContractAdressProperties;
import com.tbvtc.agriculturalcreditchainserver2025.utils.Block.AbiFileReader;
import com.tbvtc.agriculturalcreditchainserver2025.constant.RedisConstant;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import org.fisco.bcos.sdk.BcosSDK;
import org.fisco.bcos.sdk.abi.ABICodec;
import org.fisco.bcos.sdk.abi.ABICodecException;
import org.fisco.bcos.sdk.client.Client;
import org.fisco.bcos.sdk.client.protocol.model.JsonTransactionResponse;
import org.fisco.bcos.sdk.client.protocol.response.BlockNumber;
import org.fisco.bcos.sdk.crypto.CryptoSuite;
import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair;
import org.fisco.bcos.sdk.crypto.keystore.PEMKeyStore;
import org.fisco.bcos.sdk.transaction.codec.decode.TransactionDecoderInterface;
import org.fisco.bcos.sdk.transaction.codec.decode.TransactionDecoderService;
import org.fisco.bcos.sdk.transaction.manager.AssembleTransactionProcessor;
import org.fisco.bcos.sdk.transaction.manager.TransactionProcessorFactory;
import org.fisco.bcos.sdk.transaction.model.dto.CallResponse;
import org.fisco.bcos.sdk.transaction.model.dto.TransactionResponse;

import org.fisco.bcos.sdk.transaction.tools.JsonUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Scope;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.math.BigInteger;
import java.security.KeyPair;
import java.util.List;


@Component
@RequiredArgsConstructor
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) // 改为原型模式
public class BlockchainUtils {
    private final String configFilePath = "classpath:config-example.toml"; // 配置文件路径
    private final String abiPath = "classpath:/abi/"; // abi 文件路径
    private final String binPath = "classpath:/bin/";
    private final int groupId = 1;


    private static BcosSDK sdk;
    private Client client; // 客户端
    private CryptoKeyPair keyPair; // 私钥
    private AssembleTransactionProcessor transactionProcessor; // 交易处理器
    private final ResourceLoader resourceLoader;

    @Setter
    @Getter
    private TransactionDecoderInterface decoder;// 构造TransactionDecoderService实例，传入是否密钥类型参数。
    @Resource
    private ContractAdressProperties contractProperties;
    @Autowired
    private BlockBaseUtils blockBaseUtils;
    @Resource(name = "stringRedisTemplate")
    private StringRedisTemplate restTemplate;


    // 初始化 SDK 和 TransactionProcessor

    private void initialize(String landlordPemFile) throws Exception {
        if (sdk == null || client == null || keyPair == null || transactionProcessor == null) {
            ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); //
            org.springframework.core.io.Resource resource = resolver.getResource(configFilePath); // 加载配置文件
            String configFile = resource.getFile().getAbsolutePath(); // 获取配置文件路径

            // 初始化 BcosSDK 对象
            sdk = BcosSDK.build(configFile);
            // 获取 Client 对象，传入群组 ID
            client = sdk.getClient(groupId);
            // 获取当前群组对应的密码学接口
            CryptoSuite cryptoSuite = client.getCryptoSuite();
            decoder = new TransactionDecoderService(cryptoSuite);
//            BigInteger number = client.getBlockNumber().getBlockNumber();
//            System.out.println("当前群组高度为：" + number);

            // 从 PEM 文件中读取私钥
            PEMKeyStore pemKeyStore = new PEMKeyStore(landlordPemFile);
            KeyPair pair = pemKeyStore.getKeyPair();

            // 创建 CryptoKeyPair 对象
            keyPair = client.getCryptoSuite().createKeyPair(pair);

            // 获取 abi 和 bin 文件路径
            ApplicationContext context = new AnnotationConfigApplicationContext();
            resource = context.getResource(abiPath);
            String abiFilePath = resource.getFile().getAbsolutePath();

            resource = context.getResource(binPath);
            String binFilePath = resource.getFile().getAbsolutePath();

            // 初始化 AssembleTransactionProcessor
            transactionProcessor = TransactionProcessorFactory.createAssembleTransactionProcessor(client, keyPair, abiFilePath, binFilePath);
        }
    }


    // 改造后的交易方法（自动销毁）

    /**
     * @param contractName
     * @param functionName
     * @param contractAddress
     * @param params
     * @param landlordPemFile
     * @return
     * @throws Exception
     */
    public TransactionResponse sendTransaction(String contractName, String functionName, String contractAddress, List<Object> params, String landlordPemFile) throws Exception {
        initialize(landlordPemFile);
        TransactionResponse response = transactionProcessor.sendTransactionAndGetResponseByContractLoader(contractName, contractAddress, functionName, params);
        blockBaseUtils.checkIsSuccess(response, "添加农作物阶段信息为空");
        return response;
    }

    /**
     * @param contractName
     * @param functionName
     * @param contractAddress
     * @param params
     * @param landlordPemFile
     * @return
     * @throws Exception
     */
    // 改造后的查询方法（自动销毁）
    public List<Object> callContract(String contractName, String functionName, String contractAddress, List<Object> params, String landlordPemFile) throws Exception {
        initialize(landlordPemFile);
        CallResponse callResponse = transactionProcessor.sendCallByContractLoader(contractName, contractAddress, functionName, params);
        return callResponse.getReturnObject();
    }

    //获取区块高度
    public BigInteger getBlockNumber(String landlordPemFile) throws Exception {
        initialize(landlordPemFile);
        BlockNumber response = client.getBlockNumber();
        // 返回数值直接对应界面显示需求
        return response.getBlockNumber();

    }

    //最后一个区块时间戳
    public String getBlockTimestamp(String landlordPemFile) throws Exception {
        initialize(landlordPemFile);
        BigInteger blockNumber = client.getBlockNumber().getBlockNumber();
        return client.getBlockByNumber(blockNumber, true).getBlock().getTimestamp();
    }

    /**
     * 获取区块交易信息
     */

    public void getBlockTr(String landlordPemFile) throws Exception {
        //初始化SDK
        initialize(landlordPemFile);
        // 创建ABICodec实例
        ABICodec abiCodec = new ABICodec(client.getCryptoSuite());
        //获取区块链高度
        BigInteger bigBlockNumber = client.getBlockNumber().getBlockNumber();
        int blockNumber = bigBlockNumber.intValue();
        //拿取交易记录存入redis
        for (int count = blockNumber - 20; count <= blockNumber; count++) {
            JsonTransactionResponse result = client.getTransactionByBlockNumberAndIndex(
                    BigInteger.valueOf(count), BigInteger.valueOf(0x0)).getResult();
            if (result.getTo().equals(contractProperties.getFarmerManagementAddress())) {
                getResult(abiCodec, "FarmerManagement.abi", result.getInput(), result, count);
            }
            if (result.getTo().equals(contractProperties.getConsumerContractAddress())) {
                getResult(abiCodec, "ConsumerContract.abi", result.getInput(), result, count);
            }
            if (result.getTo().equals(contractProperties.getCropManagementAddress())) {
                getResult(abiCodec, "CropManagement.abi", result.getInput(), result, count);
            }
            if (result.getTo().equals(contractProperties.getLoTManagementAddress())) {
                getResult(abiCodec, "IoTManagement.abi", result.getInput(), result, count);
            }
            if (result.getTo().equals(contractProperties.getLandManagementAddress())) {
                getResult(abiCodec, "LandManagement.abi", result.getInput(), result, count);
            }
            if (result.getTo().equals(contractProperties.getLogisticContractAddress())) {
                getResult(abiCodec, "LogisticContract.abi", result.getInput(), result, count);
            }
            if (result.getTo().equals(contractProperties.getRoleManagementAddress())) {
                getResult(abiCodec, "RoleManagement.abi", result.getInput(), result, count);
            }
        }


    }

    public void getResult(ABICodec abiCodec, String fileName, String input, JsonTransactionResponse result, Integer blockNumber) throws ABICodecException {
        String abi = AbiFileReader.readAbiFile(fileName);
        List<Object> inputObject = abiCodec.decodeTransactionInput(abi, input).getLeft();
        String json = JsonUtils.toJson(inputObject);

        result.setInput(json);
        restTemplate.opsForZSet().add(RedisConstant.BLOCK_TR_KEY, String.valueOf(result),blockNumber);

    }


//        TransactionResponse farmerManagementAddress = decoder.decodeReceiptWithValues("123","adw",result);


    /**
     * 安全关闭资源
     */
    @PreDestroy
    public static void shutdown() {
        if (sdk != null) {
            sdk.stopAll();
            sdk = null;
        }
    }

}